#include <stdio.h>
#include <ctype.h>
#include <iostream>

#include "parser.h"
#include "token.h"
#include "code.h"

	
Parser::Parser()
{
	m_totalErrors = 0;
	m_code = new Code();
	m_lexan = new Scanner();
	m_symTab = new SymbolTable();
	getToken();
}
Parser::Parser(bool listing)
{
	m_totalErrors = 0;
	m_code = new Code();
	m_lexan = new Scanner();
	m_symTab = new SymbolTable();
	getToken();
}
Parser::~Parser()
{
	
}
		
SymbolTable* Parser::getSymbolTable()
{
	//return new SymbolTable;
	return m_symTab;
}

int Parser::totalErrors(){
	return m_totalErrors;
}


// Is the given tokencode in the list
bool Parser::tokenCodeIn(TokenCode tc, const TokenCode *plist)
{
	int i = 0;
	while(true)
	{
		if(plist[i] == 0 )
			return false;
		else if(plist[i] == tc)
			return true;
		i++;
	}
	return false;
}

// keep asking for tokens until token is found in the list
void Parser::recover(const TokenCode *plist)
{
	bool found = false;
	//std::cout << "Er að reyna við: " << (m_currentToken->tokenCodeToString() ) << std::endl;
	found = tokenCodeIn(m_currentToken->getTokenCode(), plist);
	while(!found)
	{
		getToken();
		if( m_currentToken->getTokenCode() == tc_EOF )
			break;
		//std::cout << "Er að reyna við: " << (m_currentToken->tokenCodeToString() ) << std::endl;
		found = tokenCodeIn(m_currentToken->getTokenCode(), plist);
	}
	if( !found )
	{
		exit(EXIT_FAILURE);
	}
	else
	{
		m_parserError = false;
		match(m_currentToken->getTokenCode());
	}
}

// ask lexical analyzer for next token
void Parser::getToken(){
	m_currentToken = m_lexan->nextToken();
	TokenCode currentTokenCode = m_currentToken->getTokenCode();
	//Moved the symboltable insertion here because compiler pt 2 assignment description 
	// states "the parser parses a stream of tokens, inserts the lexemes into the symbol table....."
	if(currentTokenCode==tc_ID || currentTokenCode==tc_NUMBER)
	{
		//inserting the lexeme into the symbol table and returning it to the current token
		SymbolTableEntry *temp = m_symTab->insert(m_currentToken->getDataValue().lexeme);
		temp->setTokenCode((char*)Token::tokenCodeToString(currentTokenCode));
//		if( m_currentToken->getDataValue().op != NULL){
//			temp->setAttribute(OpTypeName[m_currentToken->getDataValue().op]);
//		}
		m_currentToken->setSymTabEntry(temp);

	} 
	else if( m_currentToken->getTokenCode() == tc_ERROR || m_currentToken->getTokenCode() == tc_ERROR2 )
	{
		m_totalErrors++;
		setError((char*)"Illegal charcater");
		getToken();
	}
}					

TokenCode Parser::getTokenCode() {
	return m_currentToken->getTokenCode();
}

// Walk over tokencode tc.  If not a match; report an error
void Parser::match(TokenCode tc) {
	if(getTokenCode()==tc)
	{
		//printf("%s \n", m_currentToken->getDataValue().lexeme );//m_currentToken->getSymTabEntry()->getLexeme());
		//printf ("%s %s\n", "MATCH", m_currentToken->tokenCodeToString());
		getToken();
	} else {
		m_totalErrors ++;
		m_parserError = true;
		//printf ("%s %s \n", "MATCH ERROR",  m_currentToken->tokenCodeToString() );
		//getToken();
		expectedTokenCode(tc);
	}
}

void Parser::out(char const *out){
	//std::cout << out << std::endl;
}

// sets an appropriate error message
void Parser::setError(char *err){
	m_lexan->setCurrentError(err);
}

void Parser::expectedTokenCode(TokenCode tc){
	char* str = new char[200];
	strcpy(str, "Expected: ");
	strcat(str, Token::tokenCodeToString(tc));
	setError((char*)str);
}

void Parser::parseProgram(){
	//{program id ( identifier_list ) ;}
	SymbolTableEntry *programName;
	out("PROGRAM:");
	match(tc_PROGRAM);
	programName = m_currentToken->getSymTabEntry();
	if( m_parserError )  { m_parserError = false; }
	match(tc_ID);
	if( m_parserError )  { m_parserError = false; }
	match(tc_LPAREN);
	if( m_parserError )  { m_parserError = false; }
	parseIdentifierList(true, false);
	match(tc_RPAREN);
	if( m_parserError )  { m_parserError = false; }
	match(tc_SEMICOL);
	if( m_parserError )  { m_parserError = false; }
	//declerations
	parseDeclarations();
	m_code->generate(cd_GOTO, NULL, NULL, programName);
	//subprogram_declerations
	parseSubprogramDeclarations();
	//compound_statement
	createLabel(programName);
	parseCompoundStatement();
	m_code->generate(cd_RETURN, NULL, NULL, NULL);
	//{.}
	match(tc_DOT); if(m_parserError){m_parserError = false;}
}

// todo: merge these functions, from parser template in CodeGen project, with the below one fix callers to give or recive the propper parameters
	//void Parser::parseIdentifierList(EntryList *eList);
	//void Parser::parseIdentifierListMore(EntryList *eList);
	//void Parser::parseIdentifierListAndType(bool subProgramHead);
// note teachers grammar may be different

// todo: merge these functions, from parser template in CodeGen project, with the below one fix callers to give or recive the propper parameters
// note teachers grammar my be different

void Parser::parseIdentifierList(bool programHead, bool subprogramHead){
//	{id} identifier_list_LRE
	//if(getTokenCode()==tc_ID){
	out("IdentifierList:");
	if(getTokenCode()==tc_ID && programHead == false && subprogramHead == false){
		m_code->generate(cd_VAR, NULL, NULL, m_currentToken->getSymTabEntry());
		//printf ("%s \n", (char*)"parseIdentifierList:" );
		//printf ("%s \n", m_currentToken->getSymTabEntry()->getLexeme() );
	}else if(getTokenCode()==tc_ID && programHead == false && subprogramHead == true){
		m_code->generate(cd_FPARAM, NULL, NULL, m_currentToken->getSymTabEntry());
	}
	match(tc_ID);
	if( m_parserError )
	{
		if(getTokenCode()==tc_COLON)
		{
			m_parserError = false;
			return;
		}
		m_parserError = false;
		const TokenCode set[] = {tc_RPAREN, tc_SEMICOL, tc_NONE};
		recover(set);
	}
	parseIdentifierListLRE(programHead, subprogramHead);
	//} tók út if setninguna, engin tómistrengur í málreglunni
}

void Parser::parseIdentifierListLRE(bool programHead, bool subprogramHead){
// {, id} identifier_list_LRE | ε
	out("IdentifierListLRE:");
	if(getTokenCode()==tc_COMMA){
		match(tc_COMMA);
		if(getTokenCode()==tc_ID && programHead == false){
			m_code->generate(cd_VAR, NULL, NULL, m_currentToken->getSymTabEntry());
		}
		match(tc_ID);
		parseIdentifierListLRE(programHead, subprogramHead);
	}
	else if(getTokenCode() == tc_ID)
	{
		m_totalErrors++;
		expectedTokenCode(tc_COMMA);
		match(tc_ID);
		parseIdentifierListLRE(programHead, subprogramHead);
	}
}

// todo: merge this function, from parser template in CodeGen project, with the below one fix callers to give or recive the propper parameters
//void Parser::parseDeclarations(bool subProgramHead){}
// note teachers grammar my be different

void Parser::parseDeclarations(){
//declerations_LRE
	out("Declarations:");
	parseDeclarationsLRE();
}
void Parser::parseDeclarationsLRE(){
// var IDENTIFIER_LIST : TYPE ; DECLERATIONS_LRE | ε
	out("DeclarationsLRE:");
	if(getTokenCode()==tc_VAR){
		match(tc_VAR);
		parseIdentifierList(false, false);
		match(tc_COLON);
		if( m_parserError ) { m_parserError = false; }
		parseType();
		match(tc_SEMICOL);
		if( m_parserError )
		{
			m_parserError = false;
			if( getTokenCode()!=tc_VAR )
			{
				const TokenCode set[] = {tc_SEMICOL, tc_FUNCTION, tc_PROCEDURE, tc_BEGIN, tc_NONE};
				recover(set);
			}
			else
			{
				//There was no error, we were just synching on the tc_SEMICOL and since we
				//need to match tc_SEMICOL in the recover function, this match on the same
				//semicol will generate an error.  So we remove it again.
				m_totalErrors --;
				m_lexan->clearCurrentError();
			}
		}
		parseDeclarationsLRE();
	}
	else if(getTokenCode() == tc_ID)
	{
		expectedTokenCode(tc_VAR);
		m_totalErrors++;
		const TokenCode set[] = {tc_SEMICOL, tc_FUNCTION, tc_PROCEDURE, tc_BEGIN, tc_NONE};
		recover(set);
		parseDeclarationsLRE();
	}
}
void Parser::parseType(){
//standard_type | {array [ num .. num ] of} standard_type
	out("Type:");
	if(getTokenCode()==tc_ARRAY){
		match(tc_ARRAY);
		match(tc_LSQBRACKET); 	{m_parserError = false;}  //Ég recover-a allstaðar strax ef eitt eða
		match(tc_NUMBER); 		{m_parserError = false;}  //fleiri tákn vantar í array skilgrein-
		match(tc_DOTDOT); 		{m_parserError = false;}  //inguna þar sem ég veit að næsti tóki
		match(tc_NUMBER); 		{m_parserError = false;}  //mun synch-a.  Og ef ekki, þá þar næsti
		match(tc_RSQBRACKET); 	{m_parserError = false;}  //tóki. (HKH)
		match(tc_OF); 			{m_parserError = false;}
		parseStandardType();
	} else if(getTokenCode()==tc_INTEGER || getTokenCode()==tc_REAL) {
		parseStandardType();
	}
	else{
		m_totalErrors++;
		if( getTokenCode() == tc_RPAREN ){
			setError((char*)"Expected a type!");
			return;
		}
		else
		{
			setError((char*)"Expected a type!");
			const TokenCode set[] = {tc_SEMICOL, tc_VAR, tc_BEGIN};
			recover(set);
			return;
		}
	}
}

void Parser::parseStandardType(){
//{integer} | {real}   
	out("StandardType:");
	if(getTokenCode()==tc_INTEGER){
		match(tc_INTEGER);
	} else if(getTokenCode()==tc_REAL) {
		match(tc_REAL);
	}
	else{
		m_lexan->setCurrentError((char*)"Expected either INTEGER or REAL here!");
		m_totalErrors++;
	}
}


void Parser::parseSubprogramDeclarations(){
//subprogram_declerations_LRE
	out("SubprogramDeclarations:");
	parseSubprogramDeclarationsLRE();
}
void Parser::parseSubprogramDeclarationsLRE(){
//subprogram_decleration ; subprogram_declerations_LRE | ε
	out("SubprogramDeclarationsLRE:");
	//We check for funcion or procedure that appear in SubprogramDeclaration > SubprogramHead
	if(getTokenCode()==tc_FUNCTION || getTokenCode()==tc_PROCEDURE ){
		parseSubprogramDeclaration();
		match(tc_SEMICOL);
		parseSubprogramDeclarations();		
	}
}

void Parser::parseSubprogramDeclaration(){
//subprogram_head declerations compound_statement
	out("SubprogramDeclaration:");
	parseSubprogramHead();
	parseDeclarations();
	parseCompoundStatement();
	m_code->generate(cd_RETURN, NULL, NULL, NULL);
}

void Parser::parseSubprogramHead(){
//	{function id} arguments {:} standard_type {;}
//	| {procedure id} arguments {;}
	out("SubprogramHead:");
	SymbolTableEntry *funcName;
	if(getTokenCode()==tc_FUNCTION ){
		match(tc_FUNCTION);
		if( m_currentToken->getTokenCode() == tc_ID ){
			funcName = m_symTab->insert((char*)m_currentToken->getDataValue().lexeme);
			createLabel(funcName);
		}
		match(tc_ID); if(m_parserError){m_parserError = false;}

		parseArguments();
		match(tc_COLON);
		parseStandardType();
		match(tc_SEMICOL);
	} else if (getTokenCode()==tc_PROCEDURE){
		match(tc_PROCEDURE);
		if( m_currentToken->getTokenCode() == tc_ID ){
			funcName = m_symTab->insert((char*)m_currentToken->getDataValue().lexeme);
			createLabel(funcName);
		}

		match(tc_ID);if(m_parserError){m_parserError = false;}
		parseArguments();		
		match(tc_SEMICOL);
	}	
}

void Parser::parseArguments(){
//{(} parameter_list {)}	| ε
	out("Arguments:");
	if(getTokenCode()==tc_LPAREN || getTokenCode() == tc_ID ){
		match(tc_LPAREN);
		//tc_ID er ekki í mállýsingunni, en hérna er ég að reyna að recovera áður en ég fer alveg
		//út á enda
		if(m_parserError){m_parserError = false;}

		parseParameterList();
		match(tc_RPAREN);if(m_parserError){m_parserError = false;}
	}
	else
	{
		m_totalErrors++;
		const TokenCode set[] = {tc_SEMICOL, tc_VAR, tc_BEGIN, tc_NONE};
		m_lexan->setCurrentError((char*)"Missing/incorrect SubProgram Declaration");
		recover(set);
	}
}

void Parser::parseParameterList(){
//identifier_list {:} type
//| parameter_list_LRE
	//we check for semicolon to see if we are going to parameterlistlre
	out("ParameterList:");

	parseIdentifierList(false, true);
	match(tc_COLON); if(m_parserError){m_parserError = false;}
	parseType();
	parseParameterListLRE();
}
void Parser::parseParameterListLRE(){
//{;} identifier_list {:} type parameter_list_LRE | ε
	out("ParameterListLRE:");
	if(getTokenCode()==tc_SEMICOL){
		match(tc_SEMICOL);
		parseIdentifierList(false, true);
		match(tc_COLON);
		if(m_parserError){m_parserError = false;}
		parseType();
		parseParameterListLRE();				
	}
}

void Parser::parseCompoundStatement(){
//{begin} optional_statements {end}
	out("CompoundStatement:");
	match(tc_BEGIN);
	if(m_parserError){m_parserError = false;}
	parseOptionalStatements();
	match(tc_END);	
	if( m_parserError )
	{
		TokenCode set[] = {tc_ELSE, tc_SEMICOL, tc_END, tc_BEGIN, tc_DOT, tc_NONE};
		recover(set);
		m_parserError = false;
	}
}

void Parser::parseOptionalStatements(){
//statement_list | ε
	out("OptionalStatements:");
	if(getTokenCode()==tc_SEMICOL || getTokenCode()==tc_IF || getTokenCode()==tc_WHILE || getTokenCode()==tc_ID || getTokenCode()==tc_BEGIN ){
		parseStatementList();
	}
	else if(getTokenCode()==tc_ASSIGNOP)
	{
		//Hér leyfi ég villunni að fljóta inn í næsta fasa, parseStatementList()
		//og tek á villunni þar.
		parseStatementList();
	}
}

void Parser::parseStatementList(){
//statement statement_list_LRE
	//we check for semicolon to see if we are going to parameterlistlre
	//if (getTokenCode()==tc_IF || getTokenCode()==tc_WHILE || getTokenCode()==tc_ID || getTokenCode()==tc_BEGIN){
	out("StatementList:");
	parseStatement();
	parseStatementListLRE();
	
	//} tók út if setninguna því að þetta er ekki optional í málreglunni (engin tómistrengur)
}

void Parser::parseStatementListLRE(){
	//{;} statement statement_list_LRE  | ε
	out("StatementListLRE:");
	if(getTokenCode()==tc_SEMICOL ){
		match(tc_SEMICOL);
		parseStatement();
		if( m_parserError )
		{
			std::cout << "Current token er: " << (m_currentToken->tokenCodeToString() ) << std::endl;
			TokenCode set[] = {tc_SEMICOL, tc_END, tc_DOT, tc_NONE};
			recover(set);
			m_parserError = false;
		}
		parseStatementListLRE();
	}
} 

void Parser::parseStatement(){
	//	variable statement_LF
	//tókum út {id} og settum variable i stadinn
	//|	compound_statement
	//|	{if} expression {then} statement {else} statement
	//|	{while} expression {do} statement
	out("Statement:");
	SymbolTableEntry *entry, *prevEntry, *tempVar, *label, *checkLabel, *trueLabel, *whileLabel, *falseLabel, *afterLabel;

	switch (getTokenCode())
	{
		//{if} expression {then} statement {else} statement
		case tc_IF		:
			tempVar = newTemp();
			trueLabel = m_symTab->insert(m_code->newLabel());
			falseLabel = m_symTab->insert(m_code->newLabel());
			afterLabel = m_symTab->insert(m_code->newLabel());

			//IF - no comments, you ask? don't you know TAC?
			match(tc_IF);
			label = parseExpression(NULL);

			m_code->generate(cd_ASSIGN, m_symTab->insert((char*)"0"), NULL, tempVar);
			m_code->generate(cd_GOTO, NULL, NULL, trueLabel);
			createLabel(label);
			m_code->generate(cd_ASSIGN, m_symTab->insert((char*)"1"), NULL, tempVar);
			createLabel(trueLabel);
			m_code->generate(cd_EQ,tempVar, m_symTab->insert((char*)"0"),falseLabel);

			//THEN
			match(tc_THEN);
			if( m_parserError ){m_parserError = false;}
			parseStatement();
			m_code->generate(cd_GOTO, NULL, NULL, afterLabel);

			createLabel(falseLabel);
			//Optional ELSE
			if( getTokenCode()==tc_ELSE){
				match(tc_ELSE);
				if( m_parserError ){m_parserError = false;}
				parseStatement();
			}
			createLabel(afterLabel);
			break;

		//{while} expression {do} statement
		case tc_WHILE 	:
			afterLabel = m_symTab->insert(m_code->newLabel());
			whileLabel = m_symTab->insert(m_code->newLabel());
			checkLabel = m_symTab->insert(m_code->newLabel());
			createLabel(whileLabel);
			tempVar = newTemp();
			match(tc_WHILE);
			trueLabel = parseExpression(NULL);

			m_code->generate(cd_ASSIGN, m_symTab->insert((char*)"0"), NULL, tempVar);
			m_code->generate(cd_GOTO, NULL, NULL, checkLabel);
			createLabel(trueLabel);
			m_code->generate(cd_ASSIGN, m_symTab->insert((char*)"1"), NULL, tempVar);

			match(tc_DO);
			createLabel(checkLabel);
			m_code->generate(cd_EQ, tempVar, m_symTab->insert((char*)"0"), afterLabel);

			parseStatement();

			m_code->generate(cd_GOTO, NULL, NULL, whileLabel);
			createLabel(afterLabel);
			break;
		
		// variable statement_LF
		case tc_ID :
			prevEntry = m_currentToken->getSymTabEntry();
			match(tc_ID);
			parseVariable();
			parseStatementLF(prevEntry);
			break;

 		// compound_statement
		case tc_BEGIN 	: parseCompoundStatement(); break;
		
		// Error recovery line.  Ef assign op kemur vantar líklegast tc_ID fyrir framan, amk.
		// gerum við ráð fyrir því, setjum villu og höldum svo áfram að parsa eins og ef
		// tc_ID hafi komið upp
		case tc_ASSIGNOP : m_totalErrors++; setError((char*)"Expected: ID"); parseVariable(); parseStatementLF(NULL); break;

		default :
			m_lexan->setCurrentError((char*)"Expected a statement");
			m_totalErrors++;
			break;
	}
	
}

void Parser::parseStatementLF(SymbolTableEntry* prevEntry){
	//assignop EXPRESSION
	//| lb EXPRESSION rb assignop EXPRESSION
	//| ( EXPRESSION_LIST )
    //  | empty.
	SymbolTableEntry *entry;
	out("StatementLF:");
	switch (getTokenCode())
	{
		//assignop EXPRESSION
		case tc_ASSIGNOP :
			match(tc_ASSIGNOP);
			if(m_parserError){m_parserError = false;}
			entry = parseExpression(NULL);
			m_code->generate(cd_ASSIGN, entry, NULL, prevEntry);
			break;

		//| lb EXPRESSION rb assignop EXPRESSION
		case tc_LSQBRACKET :

			match(tc_LSQBRACKET);
			parseExpression(NULL);
			match(tc_RSQBRACKET);
			if(m_parserError){m_parserError = false;}
			match(tc_ASSIGNOP);
			if(m_parserError){m_parserError = false;}
			parseExpression(NULL);
			break;

		//| ( EXPRESSION_LIST )
		case tc_LPAREN :
			match(tc_LPAREN);
			entry = parseExpression(NULL);
			m_code->generate(cd_APARAM, NULL, NULL, entry);
			match(tc_RPAREN);
			m_code->generate(cd_CALL, prevEntry, NULL, NULL);
			break;

		//Error recovery match
		case tc_ID :
		case tc_NUMBER:
		case tc_ADDOP:
			m_totalErrors++;
			setError((char*)"Expected: ASSIGNOP");
			parseExpression(NULL);
			break;

		default :
			break;
	}
}

SymbolTableEntry* Parser::parseVariable(){
//VARIABLE_LF
	out("Variable:");
	return parseVariableLF();
}

SymbolTableEntry*  Parser::parseVariableLF(){
//{[} expression {]} | ε
	out("VariableLF:");
	SymbolTableEntry *entry = NULL;
	if(getTokenCode()==tc_LSQBRACKET){
		match(tc_LSQBRACKET);
		entry = parseExpression(NULL);
		match(tc_RSQBRACKET);
	}
	return entry;
}



// todo: merge this functions, from parser template in CodeGen project, with the below one fix callers to give or recive the propper parameters
	//void Parser::parseExpressionList(SymbolTableEntry* prevEntry){}
	//void Parser::parseExpressionListMore(EntryList* eList){}
// note teachers grammar my be different


void Parser::parseExpressionList(){
//expression
//| expression_list_LRE
	//we check for comma to see if we are going to expressionlistlre
	out("ExpressionList:");
	SymbolTableEntry *resultEntry;
	if(getTokenCode()==tc_COMMA ){
		parseExpressionListLRE();
	} else if (getTokenCode()==tc_MULOP || getTokenCode()==tc_ADDOP || m_currentToken->getDataValue().op==op_MINUS || m_currentToken->getDataValue().op==op_PLUS || getTokenCode()==tc_NOT || getTokenCode()==tc_NUMBER || getTokenCode()==tc_LPAREN || getTokenCode() == tc_ID) {
		resultEntry = parseExpression(NULL);
		m_code->generate(cd_APARAM, NULL, NULL, resultEntry);
		parseExpressionListLRE();
	}

}

void Parser::parseExpressionListLRE(){
//{,} expression expression_list | ε
	out("ExpressionListLRE:");
	SymbolTableEntry *resultEntry;
	if(getTokenCode()==tc_COMMA ){
		match(tc_COMMA);
		resultEntry = parseExpression(NULL);
		m_code->generate(cd_APARAM, NULL, NULL, resultEntry);
		parseExpressionListLRE();
	}
}


// todo: merge this function, from parser template in CodeGen project, with the below one fix callers to give or recive the propper parameters
//SymbolTableEntry* Parser::parseExpression(){return 0;}
// note teachers grammar may be different



SymbolTableEntry* Parser::parseExpression(SymbolTableEntry *prevEntry){
//simple_expression expression_LF
	SymbolTableEntry *resultEntry;
	out("Expression:");
	resultEntry = parseSimpleExpression(prevEntry);
	resultEntry = parseExpressionLF(resultEntry);
	
	return resultEntry;
}



SymbolTableEntry* Parser::parseExpressionLF(SymbolTableEntry *prevEntry){
//{relop} simple_expression | ε
	out("ExpressionLF:");
	SymbolTableEntry *resultEntry, *entry;
	if(getTokenCode()==tc_RELOP)
	{
		CodeOp op;
		switch( m_currentToken->getDataValue().op )
		{
			case op_EQ: op = cd_EQ; break;
			case op_GT: op = cd_GT; break;
			case op_GE: op = cd_GE; break;
			case op_LE: op = cd_LE; break;
			case op_LT: op = cd_LT; break;
			default:
				break;
		}

		match(tc_RELOP);
		resultEntry = parseSimpleExpression(prevEntry);
		entry = m_symTab->insert(m_code->newLabel());
		m_code->generate(op, prevEntry, resultEntry, entry);
		return entry;
	}
	else{
		return prevEntry;
	}

}


// todo: merge this functions, from parser template in CodeGen project, with the below one fix callers to give or recive the propper parameters
//SymbolTableEntry* Parser::parseSimpleExpression(){}
//SymbolTableEntry* Parser::parseSimpleExpressionRelop(SymbolTableEntry* prevEntry){}
//SymbolTableEntry* Parser::parseSimpleExpressionAddop(SymbolTableEntry* prevEntry){}
// note teachers grammar my be different



SymbolTableEntry* Parser::parseSimpleExpression(SymbolTableEntry *prevEntry){
//term
//| sign term
//| simple_expression_LRE
	SymbolTableEntry *resultEntry, *entry;
	out("SimpleExpression:");
	switch (getTokenCode())
	{
		//term    --  tc_MULOP eða tc_ID eða tc_LPAREN eða tc_INTEGER eða tc_NOT
		case tc_MULOP 	: parseTerm(NULL); parseSimpleExpressionLRE(NULL); break;
		case tc_LPAREN 	: resultEntry = parseTerm(NULL); parseSimpleExpressionLRE(resultEntry); break;
		case tc_NUMBER	: resultEntry = parseTerm(prevEntry); resultEntry = parseSimpleExpressionLRE(resultEntry); break;
		case tc_NOT 	: parseTerm(NULL); parseSimpleExpressionLRE(NULL); break;
	
		case tc_ADDOP 		: 
		//| sign term		
			if(m_currentToken->getDataValue().op==op_MINUS || m_currentToken->getDataValue().op==op_PLUS)
			{
				resultEntry = parseSign();
				resultEntry = parseTerm(resultEntry);
				parseSimpleExpressionLRE(resultEntry);
			} else { 		//| simple_expression_LRE	
				parseSimpleExpressionLRE(NULL);
			}
		break;

		//Error recovery
		case tc_SEMICOL : m_totalErrors++; setError((char*)"Expected: SimpleExpression"); break;

		//Þessi default lína er fyrir tc_ID token code
		default 		:
			entry = parseTerm(NULL);
			resultEntry = parseSimpleExpressionLRE(entry);
			break;
	}
	//Hilmar Kári bætti þessu inn þar sem hann fékk warning vegna þess að fallið væri ekki
	//að skila neinu
	return resultEntry;
}


SymbolTableEntry* Parser::parseSimpleExpressionLRE(SymbolTableEntry *prevEntry){
//{addop} term simple_expression_LRE | ε
	out("SimpleExpressionLRE:");
	SymbolTableEntry *resultEntry;
	CodeOp op;
	if(getTokenCode()==tc_ADDOP){
		switch( m_currentToken->getDataValue().op ){
			case op_MINUS: 	op = cd_SUB; break;
			case op_PLUS: 	op = cd_ADD; break;
			case op_OR:		op = cd_OR; break;
			default:		op = cd_ADD; break;
		}

		match(tc_ADDOP);

		resultEntry = parseTerm(prevEntry);
		SymbolTableEntry *entry = newTemp();

		m_code->generate(op, prevEntry, resultEntry, entry);
		resultEntry = parseSimpleExpressionLRE(entry);

	}
	else{
		resultEntry = prevEntry;
	}
	return resultEntry;
}


// todo: merge this functions, from parser template in CodeGen project, with the below one fix callers to give or recive the propper parameters
//SymbolTableEntry* parseTerm(){}
//SymbolTableEntry* parseTermRest(SymbolTableEntry* prevEntry){}
// note teachers grammar my be different


SymbolTableEntry* Parser::parseTerm(SymbolTableEntry *prevEntry){
//
//factor term_LRE
	SymbolTableEntry *resultEntry;
	out("Term:");

	resultEntry = parseFactor(prevEntry);
	resultEntry = parseTermLRE(resultEntry);
	return resultEntry;
}

SymbolTableEntry* Parser::parseTermLRE(SymbolTableEntry *prevEntry){
//{mulop} factor term_LRE | ε
	out("TermLRE:");
	SymbolTableEntry *resultEntry = prevEntry;
	CodeOp op;
	if(getTokenCode()==tc_MULOP){
		switch( m_currentToken->getDataValue().op ){
			case op_DIVIDE :	op = cd_DIVIDE; break;
			case op_MULT :		op = cd_MULT; break;
			case op_DIV :		op = cd_DIV; break;
			case op_AND :		op = cd_AND; break;
			case op_MOD :		op = cd_MOD; break;
			default :			op = cd_MULT; break;
		}
		match(tc_MULOP);

		resultEntry = parseFactor(prevEntry);
		SymbolTableEntry *entry = newTemp();
		m_code->generate(op, prevEntry, resultEntry, entry);

		resultEntry = parseTermLRE(entry);
	}
	return resultEntry;
}


// todo: merge this functions, from parser template in CodeGen project, with the below one fix callers to give or recive the propper parameters
//SymbolTableEntry* parseFactor();
//SymbolTableEntry* parseFactorRest(SymbolTableEntry* prevEntry);
// note teachers grammar my be different


SymbolTableEntry* Parser::parseFactor(SymbolTableEntry* prevEntry){
//variable | {id (} expression_list {)} | 
// factor_LF | {num} | {(}expression{)} | {not} factor
	SymbolTableEntry *entry, *resultEntry;
	out("Factor:");
	switch (getTokenCode())
	{
		//{(}expression{)} 
		case tc_LPAREN 	: match(tc_LPAREN); resultEntry = parseExpression(NULL); match(tc_RPAREN); break;
		
		// {num} 
		case tc_NUMBER :
			entry = m_currentToken->getSymTabEntry();
			if( prevEntry != NULL){
				if(strcmp(prevEntry->getAttribute(),(char*)"UMINUS")==0){
					m_code->generate(cd_UMINUS, entry, NULL, prevEntry );
					resultEntry = prevEntry;
				}else{
					resultEntry = entry;
				}
			}
			else{ resultEntry = entry; }

			match(tc_NUMBER);
			break;

 		// {not} factor
		case tc_NOT 	: match(tc_NOT); entry = parseFactor(NULL); resultEntry = newTemp(); m_code->generate(cd_NOT, entry, NULL, resultEntry); break;

		//Default er að vinna með tc_ID
		default : resultEntry = parseFactorLF(); break;  //Breyttum match(tc_ID) yfir í parseVariable
	}
	return resultEntry;
}

SymbolTableEntry* Parser::parseFactorLF(){
//variable | id {(} expression_list {)}
	SymbolTableEntry  *resultEntry, *functionName;
	out("FactorLF:");
	resultEntry = m_currentToken->getSymTabEntry();
	match(tc_ID);
	switch (getTokenCode())
	{
		//id {(} expression_list {)}
		case tc_LPAREN:
			match(tc_LPAREN);
			parseExpressionList();
			match(tc_RPAREN);
			m_code->generate(cd_CALL, resultEntry, NULL, NULL);
			break;
		
		//variable
		case tc_LSQBRACKET : parseVariable(); break;

		default : break;
	}
	return resultEntry;
}

SymbolTableEntry* Parser::parseSign(){
//{+} | {-}
	out("Sign:");
	SymbolTableEntry *resultEntry = NULL;
	OpType op = m_currentToken->getDataValue().op;
	if(op==op_MINUS || op==op_PLUS)
	{
		if(op==op_MINUS){
			resultEntry = newTemp();
			resultEntry->setAttribute((char*)"UMINUS");
		}
		match(tc_ADDOP);
	}
	return resultEntry;
}

/* Code generation */
SymbolTableEntry* Parser::newLabel(){
// Write the function SymbolTableEntry* Parser::newLabel() which generates 
// the next label (“lab1”,“lab2”,. . .) by calling Code::newLabel().
		// todo: implementation

// ég gerði ráð fyrir sambærilegu verklagi hér og í newTemp

	SymbolTableEntry* symTabEntry = m_symTab->insert(m_code->newLabel());
	m_code->generate(cd_LABEL, NULL, NULL, symTabEntry);
	return symTabEntry;
}

SymbolTableEntry* Parser::newTemp(){
	//Write the function SymbolTableEntry* Parser::newTemp() that 
	//generates the next temporary name (“t1”,“t2”,...) by calling
	//Code::newTemp() and inserts the temporary into the symbol table.	
	//At the end of this function (before the function returns) you need to do call:
	//m code->generate(cd VAR, NULL, NULL, entry);
	//where entry is the pointer to the symbol table entry for the temporary name. 
	//This cd VAR operation tells the interpreter to allocate memory for the temporary name. 
	//The function newTemp() returns a pointer to the symbol table entry for the temporary name.


	SymbolTableEntry* symTabEntry = m_symTab->insert(m_code->newTemp());
	m_code->generate(cd_VAR, NULL, NULL, symTabEntry);
	return symTabEntry;
}

void Parser::createLabel(SymbolTableEntry* entry){
	m_code->generate(cd_LABEL, NULL, NULL, entry);
}

CodeOp Parser::opToCode(OpType op){
		// todo: implementation
}


void Parser::parse(){
	parseProgram();
	std::cout << std::endl;
	std::cout << "Total errors: " << m_totalErrors << std::endl;
	std::cout << std::endl;
	std::cout << std::endl;
	m_symTab->print();
	//test
//	m_code->generate(cd_ADD, m_symTab->insert((char*)"i"), m_symTab->insert((char*)"1"), m_symTab->insert(m_code->newLabel()));
//	m_code->generate(cd_VAR, NULL, NULL, m_symTab->insert(m_code->newTemp()));
//	m_code->generate(cd_VAR, NULL, NULL, m_symTab->insert(m_code->newLabel()));

	if( m_totalErrors == 0 ){
		m_code->print();
	}

}


Code* Parser::getCode(){
	return m_code;
}


